package com.baofu.paycore.manager.storage.impl;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.baofu.paycore.common.enums.OperatorEnum;
import com.baofu.paycore.common.exception.ManagerErrorCode;
import com.baofu.paycore.common.exception.PayCoreManagerException;
import com.baofu.paycore.dal.mapper.PayMapper;
import com.baofu.paycore.dal.mapper.SubPayMapper;
import com.baofu.paycore.dal.model.PayDO;
import com.baofu.paycore.dal.model.SubPayDO;
import com.baofu.paycore.manager.converter.BO2DOConverter;
import com.baofu.paycore.manager.converter.DO2BOConverter;
import com.baofu.paycore.manager.model.PayBO;
import com.baofu.paycore.manager.model.SubPayBO;
import com.baofu.paycore.manager.model.SubRefundBO;
import com.baofu.paycore.manager.storage.Storage;
import com.baofu.paycore.service.facade.enums.PayCoreErrorCode;
import com.baofu.paycore.service.facade.model.PaycorePageDTO;
import com.system.commons.exception.BizServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * 支付主单存储
 *
 * <p/>
 *      1、新增订单
 *      2、更新订单
 *      3、废弃订单
 * </p>
 * User: LZQ Date: 2016/04/21  Version: 1.0
 */
@Slf4j
@Repository
public class PayManager implements Storage<PayDO> {

    /**
     * 支付主单Mapper
     */
    @Autowired
    private PayMapper payMapper;

    /**
     * 支付子单mapper
     */
    @Autowired
    private SubPayMapper subPayMapper;

    /**
     * 新增订单
     *
     * @param payDO 订单信息
     */
    @Override
    public int addOrder(PayDO payDO) {

        return payMapper.insert(payDO);
    }

    /**
     * 更新订单
     *
     * @param payDO 订单信息
     */
    @Override
    public int modifyOrder(PayDO payDO) {

        return payMapper.updateStatusByPayNo(payDO.getPayNo(), payDO.getStatus());
    }

    /**
     * 废弃订单
     *
     * @param payDO 订单信息
     */
    @Override
    public int deleteOrder(PayDO payDO) {
        return 0;
    }


    /**
     * 根据支付单号获取交易
     *
     * @param payNo         支付单号
     * @return              支付订单
     */
    public PayDO queryByPayNo(String payNo){

        PayDO payDO = payMapper.selectByPayNo(payNo);

        if(payDO == null){
            log.error("查询结果集为空:{}",payNo);
            throw new BizServiceException(PayCoreErrorCode.EMPTY_QUERY_RESULT);
        }
        return payDO;
    }

    /**
     * 根据订单号和交易流水号查询交易
     *
     * @return 交易对象
     */
    public PayDO queryByOrderNo(String requestOrderNo,String requestBizNo,Date requestDate,String requestSystem){
        PayDO resPayDO = payMapper.selectByOrderNo(requestOrderNo, requestBizNo, requestDate,requestSystem);
        if(resPayDO == null){
            log.error("查询结果集为空:{} {} {}",requestOrderNo,requestBizNo,requestDate);
            throw new BizServiceException(PayCoreErrorCode.EMPTY_QUERY_RESULT);
        }
        return resPayDO;
    }

    /**
     * 查询锁定支付订单
     *
     * @param requestOrderNo   请求订单号
     * @param requestBizNo     请求流水号
     * @return                 支付信息
     */
    public PayDO queryByPayNoForUpdate(String requestOrderNo, String requestBizNo,String requestSystem){

        log.debug("支付主单查询锁定请求参数, requestOrderNo:{},requestBizNo:{}, requestSystem:{}",
                requestOrderNo, requestBizNo, requestSystem);

        PayDO payDO;
        try{
            payDO = payMapper.selectByPayNoForUpdate(requestOrderNo, requestBizNo,requestSystem);
        } catch (Exception e) {
            log.error("查询锁定支付订单失败, error:{}",PayCoreErrorCode.DATABASE_FOR_UPDATE_EXCEPTION);
            throw new PayCoreManagerException(PayCoreErrorCode.DATABASE_FOR_UPDATE_EXCEPTION);
        }
        if(null == payDO) {
            log.error("查询锁定支付订单失败, error:{}",PayCoreErrorCode.ORIG_ORDER_NOT_EXIST);
            throw new BizServiceException(PayCoreErrorCode.ORIG_ORDER_NOT_EXIST);
        }
        return payDO;
    }

    /**
     * 更新订单
     *
     * @param payBO 订单信息
     */
    public void modifyRefundAmt(PayBO payBO) {

        log.debug("更新支付主单退款金额, parameter:{}",payBO);
        int updateRows = payMapper.updateRefundAmt(payBO.getPayNo(), payBO.getRefundAmt(),
                OperatorEnum.UPDATED_BY.getCode());
        if(updateRows > 1){
            log.error("更新支付主单退款金额失败, error:{}",PayCoreErrorCode.UPDATE_DATA_NOT_ONE);
            throw new PayCoreManagerException(PayCoreErrorCode.UPDATE_DATA_NOT_ONE);
        }
    }

    /**
     * 分页查询支付信息
     *
     * @param payBO         请求参数
     * @param beginPage     开始行
     * @param endPage       结束行
     * @return              支付信息
     */
    public List<PayDO> queryPayPage(PayBO payBO,PaycorePageDTO paycorePageDTO, Integer beginPage, Integer endPage){

        return payMapper.query(BO2DOConverter.getPayDOByPayBO(payBO), paycorePageDTO.getStartDate(),paycorePageDTO.getEndDate(),beginPage, endPage);
    }

    /**
     * 查询支付信息总数
     *
     * @param payBO         请求参数
     * @return              总数
     */
    public int queryPayCount(PayBO payBO, PaycorePageDTO paycorePageDTO){
        return payMapper.queryPageCount(BO2DOConverter.getPayDOByPayBO(payBO),paycorePageDTO.getStartDate(),paycorePageDTO.getEndDate());
    }

    /**
     * 获取支付信息
     *
     * @param requestOrderNo        请求订单号
     * @param requestBizNo          请求业务编号
     * @param requestDate           请求时间
     * @param requestSystem         请求系统
     * @return                      支付信息
     */
    public PayBO queryPayInfo(String requestOrderNo, String requestBizNo, Date requestDate, String requestSystem) {
        PayDO payDO = this.queryByOrderNo(requestOrderNo, requestBizNo, requestDate, requestSystem);
        List<SubPayDO> subPayDOs = subPayMapper.selectByPayNo(payDO.getPayNo());
        if (CollectionUtils.isEmpty(subPayDOs)) {
            log.error("支付子单信息为空,支付单号:{}", payDO.getPayNo());
            throw new BizServiceException(PayCoreErrorCode.EMPTY_QUERY_RESULT, "支付子单信息为空");
        }
        return DO2BOConverter.buildPayBO(payDO, subPayDOs);
    }

    /**
     * 更新订单, 支付单退款金额回退
     *
     * <p>在退款交易失败时，支付单退款金额需要回退</p>
     *
     * @param payBO 订单信息
     */
    @Transactional(isolation = Isolation.DEFAULT,
            propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void modifyRefundAmtByFallback(PayBO payBO) {

        log.debug("更新支付主单退款金额, parameter:{}",payBO);

        int updateRows = payMapper.updateRefundAmtByFallback(payBO.getPayNo(), payBO.getRefundTradeAmt(),
                OperatorEnum.UPDATED_BY.getCode());
        if(updateRows != 1){
            log.error("更新支付主单退款金额失败, error:{}",PayCoreErrorCode.UPDATE_DATA_NOT_ONE);
            throw new PayCoreManagerException(PayCoreErrorCode.UPDATE_DATA_NOT_ONE);
        }

        List<SubPayBO> subPayBOs = payBO.getSubPayList();
        if(CollectionUtils.isEmpty(subPayBOs)){
            return;
        }
        for(SubPayBO subPayBO : subPayBOs) {

            int subUpdateRows = subPayMapper.updateRefundAmtByFallback(subPayBO.getFundDetailNo(),
                    subPayBO.getRefundTradeAmt(), OperatorEnum.UPDATED_BY.getCode());
            if(subUpdateRows != 1){
                log.error("更新支付明细退款金额失败, error:{}",PayCoreErrorCode.UPDATE_DATA_NOT_ONE);
                throw new PayCoreManagerException(PayCoreErrorCode.UPDATE_DATA_NOT_ONE);
            }
        }
    }
}
